﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ParserGenerator.Collections;

namespace ParserGenerator.Extensions
{
    public static class IListExtensions
    {
        public static ReadOnlyCollection<T> AsReadOnly<T>(this IList<T> list)
        {
            if (list == null)
                throw new ArgumentNullException(nameof(list));
            return new ReadOnlyCollection<T>(list);
        }

        public static ReadOnlyLinkedList<T> AsReadOnly<T>(this LinkedList<T> list)
        {
            if (list == null)
                throw new ArgumentNullException(nameof(list));
            return new ReadOnlyLinkedList<T>(list);
        }

        public static int ListCompareTo<T>(this IReadOnlyCollection<T> list, IReadOnlyCollection<T> other)
        {
            if (list == other)
                return 0;
            if (list == null)
                return -1;
            if (other == null)
                return 1;
            using (IEnumerator<T> e1 = list.GetEnumerator())
            using (IEnumerator<T> e2 = other.GetEnumerator())
            {
                while (true)
                {
                    if (!e1.MoveNext())
                        return e2.MoveNext() ? -1 : 0;
                    if (!e2.MoveNext())
                        return 1;
                    int t = ICollectionExtensions.ItemCompareTo(e1.Current, e2.Current);
                    if (t != 0)
                        return t;
                }
            }
        }

        public static bool ListEquals<T>(this IReadOnlyCollection<T> list, IReadOnlyCollection<T> other)
        {
            if (list == other)
                return true;
            if (list == null)
                return false;
            if (other == null)
                return false;
            if (list.Count != other.Count)
                return false;
            using (IEnumerator<T> e1 = list.GetEnumerator())
            using (IEnumerator<T> e2 = other.GetEnumerator())
            {
                while (e1.MoveNext() && e2.MoveNext())
                    if (!Equals(e1.Current, e2.Current))
                        return false;
                return true;
            }
        }

        public static int GetListHashCode<T>(this IReadOnlyCollection<T> list)
        {
            if (list == null)
                throw new ArgumentNullException(nameof(list));
            int h = list.Count;
            foreach (T item in list)
            {
                int c = ICollectionExtensions.GetItemHashCode(item);
                h = ICollectionExtensions.CombineHashCodes(h, c);
            }
            return h;
        }

        public static IEnumerable<KeyValuePair<T, T>> EnumPairs<T>(this IReadOnlyList<T> list)
        {
            if (list == null)
                throw new ArgumentNullException(nameof(list));
            for (int i = 0; i < list.Count; i++)
            {
                T x = list[i];
                for (int j = i + 1; j < list.Count; j++)
                    yield return new KeyValuePair<T, T>(x, list[j]);
            }
        }
    }
}
